﻿/********************************************************************************/
/* 	map.d																		*/
/*------------------------------------------------------------------------------*/
/*	製作		（　゜ワ゜）ノ　／　松久貫太									*/
/*	製作開始　	2008/01/03														*/
/*	MAIL		omega@personal.email.ne.jp										*/
/*	URL		http://nagoya.cool.ne.jp/o_mega										*/
/*																				*/
/*	このソースは「やわらかライセンス」の元で配布されています。					*/
/*-更新履歴---------------------------------------------------------------------*/
/*	2008/01/04																	*/
/*-その他-----------------------------------------------------------------------*/
/*	なし																		*/
/********************************************************************************/

private import gamecore;
private import hell2;
private import boot;
private import actor;
private import vector;
private import keypad;

private import character;


//********************************************************************************
// マップちっぷ
//********************************************************************************

const static int CHIP_SIZE = 32;

class MapChip{
	enum TYPE{
		NONE = 0,
		CURSOR = 0,
		MOVIE = 1,
		FENCE,
	}
	const static string name[] = ["NONE" , "MOVIE" , "FENCE"];
	
	const static int TYPEDRAW_LOOP = 16;
	static int GRASS_COLOR_R = 128;
	static int GRASS_COLOR_G = 128;
	static int GRASS_COLOR_B = 128;
	
	
	double grass;
	
	TYPE type;
	
	this(){
		GRASS_COLOR_R = configparser.getint("MAP_GRASS_COLOR_R");
		GRASS_COLOR_G = configparser.getint("MAP_GRASS_COLOR_G");
		GRASS_COLOR_B = configparser.getint("MAP_GRASS_COLOR_B");
		
		init();
	}
	
	void init(){
		grass = 0;
		type = TYPE.NONE;
	}
	
	void drawBase(double x,double y){
		/* 本来はCHIP_SIZE * CHIP_SIZE分コピーすべきだが、高速化のため下半分だけコピーする */
		Hell_drawTexture("char" , x , y + CHIP_SIZE / 2
			,0
			,CHIP_SIZE / 2
			,CHIP_SIZE
			,CHIP_SIZE / 2);
		
		/* 本来のコード
		Hell_drawTexture("char" , x , y
			,0
			,0
			,CHIP_SIZE
			,CHIP_SIZE);
		*/
	}
	void draw(double x , double y,int anime = 0){
		if(type == TYPE.NONE){
			// 芝
			if(getGrassLevel() < 1) return;
			Hell_drawTexture("char" , x , y
				,0
				,CHIP_SIZE * getGrassLevel()
				,CHIP_SIZE
				,CHIP_SIZE,1,1,0, GRASS_COLOR_R,GRASS_COLOR_G,GRASS_COLOR_B);
		}else{
			// オブジェクト
			Hell_drawTexture("char" , x , y
				,CHIP_SIZE * anime + CHIP_SIZE
				,CHIP_SIZE * (type % TYPEDRAW_LOOP)
				,CHIP_SIZE
				,CHIP_SIZE);
		}
	}
	
	static void drawCursor(double x,double y,int anime = 0){
		Hell_drawTexture("char" , x , y ,CHIP_SIZE * anime + CHIP_SIZE ,0
			,CHIP_SIZE
			,CHIP_SIZE);
	}
	
	int getGrassLevel(){
		if(grass < 10){
			return 0;
		}else if(grass < 20){
			return 1;
		}else if(grass < 40){
			return 2;
		}else if(grass < 80){
			return 3;
		}else{
			return 4;
		}
	}
}

//********************************************************************************
// マップ
//********************************************************************************

class Map{
	const static double DRAW_CHIP_W = 12.0;
	const static double DRAW_CHIP_H = 6.0;
	const static double MOUSE_OFS_X = 16.0;
	const static double MOUSE_OFS_Y = 18.0;
	
	static double MAP_GRASS_AFFECT = 0.90;
	static double MAP_GRASS_AFFECT_LIMIT = 0.3;
	
	static int MAP_REFRESH_INTERVAL = 10;
	
	static double MOVIE_GRASS_FEED = 200;
	
	GameMain gamemain;
	MapChip[] map;
	bool[] movable_map;
	
	int width;
	int height;
	int timer;
	
	double draw_ofs_x;
	double draw_ofs_y;
	
	this(GameMain gamemain , int width , int height){
		this.gamemain = gamemain;
		this.width = width;
		this.height = height;
		
		MAP_GRASS_AFFECT = configparser.getfloat("MAP_GRASS_AFFECT");
		MAP_REFRESH_INTERVAL = configparser.getint("MAP_REFRESH_INTERVAL");
		MOVIE_GRASS_FEED = configparser.getfloat("MAP_MOVIE_GRASS_FEED");
		MAP_GRASS_AFFECT_LIMIT = configparser.getfloat("MAP_GRASS_AFFECT_LIMIT");
		
		this.map = new MapChip[width * height];
		foreach(inout m;map) m = new MapChip();
		
		this.movable_map = new bool[width * height];
		foreach(inout mm;movable_map) mm = true;
		
		this.draw_ofs_x = 0;
		this.draw_ofs_y = 0;
		
		timer = 0;
	}
	
	void update(){
		timer++;
		
		int[] vecx = [ -1 ,  0 ,  1 ,  0 ];
		int[] vecy = [  0 , -1 ,  0 ,  1 ];
		
		for(int x = 0;x < width;x++){
			// 適当に負荷分散してみる
			if(timer % MAP_REFRESH_INTERVAL != x % MAP_REFRESH_INTERVAL) continue;
			
			for(int y=0;y < height;y++){
				MapChip here = toMap(x,y);
				if(isMap(x,y, MapChip.TYPE.NONE)){
					// 何もない場合は隣接マスから芝えねるぎーを算出する
					int grass_density = 0;
					
					// 周りの芝濃度を算出する
					for(int v=0;v < vecx.length ; v++){
						int px = x + vecx[v];
						int py = y + vecy[v];
						
						if(inRange(px,py)){
							MapChip m = toMap(px,py);
							grass_density += m.grass;
						}
					}
					// 濃度にあわせようとする
					grass_density /= vecx.length;//grass_cnt;
					
					if(here.grass < grass_density){
						double a = grass_density - here.grass;
						if(a > MAP_GRASS_AFFECT_LIMIT) a = MAP_GRASS_AFFECT_LIMIT;
						here.grass += a;
					}				
				}else if(isMap(x,y, MapChip.TYPE.MOVIE)){
					// 動画がある場合は無条件に濃度上昇
					here.grass = MOVIE_GRASS_FEED;
				}
			}
		}
		
		updateMovableMap();
	}
	
	// キャラクタ判定用・移動可能マップを更新する
	void updateMovableMap(){
		for(int x = 0;x < width;x++){
			for(int y=0;y < height;y++){
				bool res = true;
				
				if(map[x + y * width].type != MapChip.TYPE.NONE) res = false;
				
				movable_map[x + y * width] = res;
			}
		}
		
		CharacterPool cp = gamemain.charpool;
		foreach(c;cp.actors){
			if(c.exist){
				Vec3 p = c.getPosition();
				if(inRange(cast(int)p.x , cast(int)p.y) && c.isBlocking())
					movable_map[cast(int)p.x + cast(int)p.y * width] = false;
			}
		}
	}
	
	// 作画
	// 参照・キャラクタバケットソート
	void draw(){
		// Map座標系で作画範囲をクリップ
		int x_st = toRoundMapX(toMapX(0,0));
		int y_st = toRoundMapY(toMapY(gamemain.getScreenWidth(),0));
		int x_ed = toRoundMapX(toMapX(gamemain.getScreenWidth() , gamemain.getScreenHeight()) + 2);
		int y_ed = toRoundMapY(toMapY(0 , gamemain.getScreenHeight()) + 2);
		
		for(int x = x_st;x < x_ed;x++){
			for(int y = y_st;y < y_ed;y++){
				double dx = toViewX(x,y);
				double dy = toViewY(x,y);
				
				if(dx < -32 || dy < -32 || dx > gamemain.getScreenWidth() + 32
					|| dy > gamemain.getScreenHeight() + 32) continue;
				
				toMap(x,y).drawBase(dx , dy);
				if(isMap(x,y, MapChip.TYPE.NONE)) toMap(x,y).draw(dx , dy , (timer / 5) % 4);
			}
		}
		
		for(int x = x_st;x < x_ed;x++){
			for(int y = y_st;y < y_ed;y++){
				double dx = toViewX(x,y);
				double dy = toViewY(x,y);
				
				if(dx < -32 || dy < -32 || dx > gamemain.getScreenWidth() + 32
					|| dy > gamemain.getScreenHeight() + 32) continue;
				
				if(!isMap(x,y, MapChip.TYPE.NONE)) toMap(x,y).draw(dx , dy , (timer / 5) % 4);
				gamemain.charpool.drawAtMap(x,y);
			}
		}
	}
	
	bool set(int x,int y,MapChip.TYPE type){
		if(!inRange(x,y)) return false;
		
		MapChip m = toMap(x,y);
		m.type = type;
		m.grass = 0;
		return true;
	}
	
	// 芝刈
	bool setGrass(int x,int y,double grass){
		if(!inRange(x,y)) return false;
		
		MapChip m = toMap(x,y);
		m.grass = grass;
		return true;
	}
	
	double getGrass(int x,int y){
		if(!inRange(x,y)) return 0;
		
		MapChip m = toMap(x,y);
		return m.grass;
	}
	
	int getGrassLevel(int x,int y){
		if(!inRange(x,y)) return 0;
		
		MapChip m = toMap(x,y);
		return m.getGrassLevel();
	}
	
	bool isMap(int x,int y,MapChip.TYPE type){
		if(!inRange(x,y)) return false;
		
		MapChip m = toMap(x,y);
		return m.type == type;
	}
	
	// 座標変換
	double toViewX(double x,double y){return (x - y) * DRAW_CHIP_W + draw_ofs_x;}
	double toViewY(double x,double y){return (x + y) * DRAW_CHIP_H + draw_ofs_y;}
	int toMapX(int x,int y){
		return cast(int)(((x - draw_ofs_x - MOUSE_OFS_X) / DRAW_CHIP_W + (y - draw_ofs_y - MOUSE_OFS_Y) / DRAW_CHIP_H) / 2);
	}
	int toMapY(int x,int y){
		return cast(int)(((y - draw_ofs_y - MOUSE_OFS_Y) / DRAW_CHIP_H - (x - draw_ofs_x - MOUSE_OFS_X) / DRAW_CHIP_W) / 2);
	}
	
	int toRoundMapX(int x){
		if(x < 0) return 0;
		if(x >= width) return width;
		return x;
	}
	int toRoundMapY(int y){
		if(y < 0) return 0;
		if(y >= height) return height;
		return y;
	}
	
	bool inRange(int x,int y){
		return x >= 0 && y >= 0 && x < width && y < height;
	}
	
	MapChip toMap(int x,int y){return map[x + y * width];}
	bool isMovable(int x,int y){
		if(inRange(x,y)) return movable_map[x + y * width];
		return true;	// 欄外は移動可能領域
	}
	
	int count(MapChip.TYPE type){
		int result = 0;
		foreach(m;map){
			if(m.type == type) result++;
		}
		return result;
	}
}

